Repository navigation
ci(tss): gated TSS shadow publish lane v2 (TIN-3026) - #263
Jesssullivan wants to merge 5 commits into
Conversation
|
Operator ceremony for the first tss publish (run in order; nothing here is performed by an agent):
Merging this PR alone changes nothing on any served surface. |
|
Reworked at HEAD after the adversarial review of the first cut (blocker confirmed: the publish job executed PR-head code in the same job that held the Cloudflare token).
Open from the review, deliberately not changed here: the pre-publish Local: |
|
Three things before this can be dispatched (the job split and served-SHA
|
|
Fixed at HEAD: (1) the kill switch is now re-read by Actions at deploy-job start ( |
tss.tinyland.dev has had no publisher since the legacy shadow workflow was retired on 2026-08-13; it still serves the 2026-07-14 build. This adds the default-branch-owned, dispatch-only lane TIN-3026 names as the separately authorized apply path for the public noindex development shadow: - resolves an exact current-main SHA or an open same-repo PR head, requires a successful canonical CI run at that SHA with build-and-test and bazel-remote-gates green, and fails closed unless deploy=true and BLOG_TSS_PUBLISH_ENABLED=true; - builds with PUBLIC_DEPLOY_TIER=shadow (site-wide noindex + source-sha meta, validated by validate-deploy-tier-output.mjs), records the static digest, revalidates the kill switch and the source immediately before publish, and refuses the production Pages project by name; - publishes to CLOUDFLARE_PAGES_TSS_PROJECT_NAME only (repo var, required). Resolver fixtures cover every refusal path; the workflow-authority contract pins the lane shape and forbids production reach or manual carriers. AGENTS.md registers the lane; docs/tss-shadow-publish.md records the ceremony.
…ified deploy Review finding on the first cut: the publish job ran npm ci / npm run build on the requested PR head in the same job that held the Cloudflare account token, so source-tree code could reach the token and the production-project name guard was decorative. The lane now mirrors shadow-source-build-v2 → shadow-source-publish-v2: the build job has contents:read only and no secret, uploads the built tree with its digest; the deploy job never checks out or executes source-tree code, re-derives the digest from the downloaded artifact, revalidates the kill switch and the source, and only then runs wrangler against the artifact. Also: the Pages project name is validated as a slug and refused when it is the production project (trailing whitespace can no longer slip past an exact compare into a shell word), the project defaults to tss-shadow as recorded in docs/dns-architecture.md, the canonical-CI lookup filters by head_sha, the shadow ships robots.txt Disallow plus an X-Robots-Tag header alongside the HTML meta, the run fails unless tss.tinyland.dev serves the published source SHA within four minutes, the authority test pins the single trigger, the build/deploy split, workflow_id ci.yml and the step order, and AGENTS.md no longer says Cloudflare publication comes only from the production lane.
…iables API Review finding: GITHUB_TOKEN carries no Variables permission, so the getRepoVariable recheck copied from the sibling v2 lanes would 403 and refuse every publish after a full build. The deploy job is now gated with 'if: vars.BLOG_TSS_PUBLISH_ENABLED == true', which Actions resolves when the job is scheduled (after the build), and the pre-publish step keeps the source freshness checks (main head / PR still open at the exact SHA). The authority contract now forbids getRepoVariable in this lane.
2b6f2bd to
8929f27
Compare
8929f27 to
55f3865
Compare
|
Closed as superseded by #281 (exact-source TSS Pages direct publisher, head d756ee2), per operator ruling TIN-3692 RM12 (comment bb016df6) and addendum section 4 ("blog: close #263 as superseded by #281"). Head 55f3865 stays reachable on branch jess/tin-3026-tss-shadow-publish-v2; the branch is not deleted. TIN-3026 / TIN-2727. Authority: R-HOOK-CONVERGENCE-20261004 / R-N11 / R-N13. |
Why
tss.tinyland.devis already publicly resolvable but still serves the old Pages build (1784027104867); it is not a current static shadow of the reviewed Tinyland blog. The site is a separately-provisioned Pages project, so changing the canonicaljesssullivan.github.iodeployment workflow or rebinding the public route would be unsafe. This draft adds a dedicated, opt-in dispatch path for that project only.What changed
tss-shadow-publish-v2.yml,workflow_dispatch/ typedrepository_dispatchonly;BLOG_TSS_PUBLISH_ENABLEDto false and refuses to publish without it;CLOUDFLARE_PAGES_TSS_PROJECT_NAME, failing closed if it is blank or equals the canonical project;HEAD, resolves the successful build provenance with existing bounded pagination/cross-checks, and uses its exact artifact;Not in this PR (operator ceremony)
tss-shadowproject, butCLOUDFLARE_PAGES_TSS_PROJECT_NAMEis not configured in repository metadata.BLOG_TSS_PUBLISH_ENABLED=true, dispatch against a fresh successful canonical build, then reset it to false and record the live SHA/headers.Merging this PR publishes nothing:
BLOG_TSS_PUBLISH_ENABLEDis currently absent (therefore false) and the lane has no non-dispatch trigger. After it lands, the operator must configure the dedicated TSS project variable, establish the TIN-2727 credential evidence, and deliberately enable the TSS switch for an exact-SHA dispatch. The former TIN-2801 publication hold was lifted by operator ruling on 2026-09-22; it is not a condition of this lane.Evidence
GET https://tss.tinyland.dev/bloghad notinyland-source-shameta tag;GET /robots.txtwasAllow: /;GET /_app/version.jsonwas1784027104867.docs/blog-shadow-preview.md,docs/dns-and-cloudflare-architecture.md.Validation
node --checkfor the workflow’s embedded scripts;